'''
Created on Jun 9, 2011

@author: Kathy Benitez
'''
import unittest, pickle, csv
import popStats, policyEvaluation

def setUpTestDatabase():
    ps = popStats.PopStatsCounty(url="sqlite://")
    ps.createTables()
    f = open("../data/test/setup/testFieldNames.csv")
    cf = csv.DictReader(f, delimiter=',')
    for row in cf:
        ps.description.insert().values(**row).execute()
    
    r = open("../data/test/setup/testData.csv")
    cr = csv.DictReader(r, delimiter=',')
    for row in cr:
        ps.records.insert().values(**row).execute()
    return ps

class PopStatsTestCase(unittest.TestCase):
    def setUp(self):
        """
        Create a tiny sqlite database to test the functionality of the policyEvaluation module
        """
        self.ps = setUpTestDatabase()
    def tearDown(self):
        pass

class SetupQueryTestCase(PopStatsTestCase):
    def setUp(self):
        PopStatsTestCase.setUp(self)
        self.q = self.ps.setupQuery()
    def testBasic(self):
        self.assertIn('pop', self.q.columns, "Population field needed for calculation")
        self.assertIn('minage', self.q.columns, "Minage field needed for calculation")
        self.assertIn('maxage', self.q.columns, "Maxage field needed for calculation")
    def testExecution(self):
        result = self.ps.xn.execute(self.q)
        self.assertGreater(len(result.fetchall()), 0, "No result returned from general select")
        
class HowManyMatchesTestCase(PopStatsTestCase):
    def testNoSpecifications(self):
        """No specifications should yield entire population"""
        matches = self.ps.howManyMatches({}) 
        self.assertEqual(matches, 11085) 
    
    def testEverythingSpecified(self):
        """Everything specified"""
        matches = self.ps.howManyMatches({"race":["White alone"],
                                  "sex":["Female"],
                                  "age":[34]})
        self.assertEqual(matches,1002)

    def testNonexistentCategoryName(self):
        """Nonexixtent Category"""
        self.assertRaises(TypeError, 
                          self.ps.howManyMatches, 
                          {"salary":[56000]})

#    def testNonexistentVocabItem(self):
#        """Item not in vocabulary"""
#        self.assertRaises(ValueError,
#                          self.ps.howManyMatches,
#                          {"race":["Asian alone"]})

    def testMultipleValues(self):
        """Multiple values for a single category"""
        matches = self.ps.howManyMatches({"race":["White alone"],
                                  "sex":["Female"],
                                  "age":[34,35]})
        self.assertEqual(matches,2369)
    def testOldAge(self):
        """Dealing with ages over 100"""
        matches = self.ps.howManyMatches({"race":["White alone"],
                                  "sex":["Female"],
                                  "age":[100, 101, 102, 103, 104]})
        self.assertEqual(matches,502)
    def testSubOldAge(self):
        """Single value of field resported in range (age)"""
        matches = self.ps.howManyMatches({"race":["White alone"],
                                  "sex":["Female"],
                                  "age":[100]})
        self.assertEqual(matches,100.4) 

class PopStatsZipTestCase(PopStatsTestCase):
    pass

class PopStatsCountyTestCase(PopStatsTestCase):
    pass

##################################################################
##################################################################
##################################################################
class PolicyStringTestCase(unittest.TestCase):
    pass
class InitTestCase(PolicyStringTestCase):
    def passNullArg(self):
        pass
    def passStringOfBinary(self):
        p = policyEvaluation.PolicyString('10')
        self.assertEqual(p[0],1)
        self.assertEqual(p[1],0)
        self.assertEqual(p.size(), 2)
    def passListOfBinary(self):
        p = policyEvaluation.PolicyString(['1', '0'])
        self.assertEqual(p[0],1)
        self.assertEqual(p[1],0)
        self.assertEqual(p.size(), 2)
    def passListOfBoolean(self):
        p = policyEvaluation.PolicyString([True, False])
        self.assertEqual(p[0],1)
        self.assertEqual(p[1],0)
        self.assertEqual(p.size(), 2)
class SizeTestCase(PolicyStringTestCase):
    def emptyPolicy(self):
        p = policyEvaluation.PolicyString(None)
        self.assertEqual(p.size(), 0)
    def multipleOfEight(self):
        p = policyEvaluation.PolicyString('00001111')
        self.assertEqual(p.size(), 8)
    def notMultipleOfEight(self):
        p = policyEvaluation.PolicyString('000111')
        self.assertEqual(p.size(), 6)
class MostSpecificTestCase(PolicyStringTestCase):
    def correctLength(self):
        for i in range(0,100):
            p = policyEvaluation.PolicyString.mostSpecific(i)
            self.assertEqual(i, p.size())
    def correctValue(self):
        max = 100
        p = policyEvaluation.PolicyString.mostSpecific(max)
        for i in range(0,max):
            self.assertEqual(p[i], 1)
class MostGeneralTestCase(PolicyStringTestCase):
    def correctLength(self):
        for i in range(0,100):
            p = policyEvaluation.PolicyString.mostGeneral(i)
            self.assertEqual(i, p.size())
    def correctValue(self):
        max = 100
        p = policyEvaluation.PolicyString.mostGeneral(max)
        for i in range(0,max):
            self.assertEqual(p[i], 0)

class RandomTestCase(PolicyStringTestCase):
    def correctLength(self):
        for i in range(0,100):
            p = policyEvaluation.PolicyString.random(i)
            self.assertEqual(i, p.size())
    def correctValue(self):
        p = policyEvaluation.PolicyString.random(100)
        self.assertNotEqual(p, policyEvaluation.PolicyString.mostGeneral(max))
        self.assertNotEqual(p, policyEvaluation.PolicyString.mostSpecific(max))

            
##################################################################
##################################################################
##################################################################

class DatasetTestCase(unittest.TestCase):
    def setUp(self):
        vocab = pickle.load(open("../data/test/vocab.pckl", 'r'))   
        fields = {0:"race", 1:"sex", 2:"age", 3:"county"}
        dset = csv.reader(open("../data/test/dsets/testDataSource_5.csv", 'r'),delimiter=",")
        self.ds = policyEvaluation.Dataset(fields,dset,vocab)

class ConstructorTestCase(DatasetTestCase):
    pass
class ToAbstractTestCase(DatasetTestCase):
    def testSetUp(self):
        pass
    def testEmptyArgs(self):
        self.assertRaises(TypeError, policyEvaluation.Dataset.toAbstract, None, None)
    def testSimpleCase(self):
        r = policyEvaluation.Dataset.toAbstract([("word1",), ("word1",), ("word1",)], {(1):"word1", (2):"word2"})
        self.assertEqual(r, {(1,):3})
    def testMultiWordDatasetItems(self):
        r = policyEvaluation.Dataset.toAbstract([("word1", "word2"), ("word2",)], {(1):"word1", (2):"word2"})
        self.assertItemsEqual(r, {(1,2):1, (2,):1})
    def testNotInVocab(self):
        self.assertRaises(ValueError, policyEvaluation.Dataset.toAbstract,
                          [("notInVocab",), ("word2",)], 
                          {(1):"word1", (2):"word2"})
class ApplyPolicyTestCase(DatasetTestCase):
    def testMostSpecific(self):
        newDs = self.ds.applyPolicy(policyEvaluation.PolicyString.mostSpecific(9))
        for k in newDs:
            self.assertEqual(newDs[k], self.ds[k])
    def testMostGeneral(self):        
        newDs = self.ds.applyPolicy(policyEvaluation.PolicyString.mostGeneral(9))
        for k in newDs:
            self.assertEqual(newDs[k], 5)
    def testPolicy1(self):
        newDs = self.ds.applyPolicy(policyEvaluation.PolicyString('101001010'))
        self.assertEqual(newDs[((0,0),(1,0),(1,1),(2,1),(2,2),(2,3),(3,0),(3,1))],1)
        self.assertEqual(newDs[((0,0),(1,0),(1,1),(2,4),(2,5),(3,0),(3,1))],3)
        self.assertEqual(newDs[((0,1),(1,0),(1,1),(2,1),(2,2),(2,3),(3,0),(3,1))],1)
    def testPolicy2(self):    
        newDs = self.ds.applyPolicy(policyEvaluation.PolicyString('010011011'))
        self.assertEqual(newDs[((0,0),(0,1),(1,0),(2,0),(2,1),(2,2),(3,0))],2)
        self.assertEqual(newDs[((0,0),(0,1),(1,1),(2,4),(2,5),(3,1))],2)
        self.assertEqual(newDs[((0,0),(0,1),(1,0),(2,4),(2,5),(3,0))],1)
class GetSpecificationsTestCase(DatasetTestCase):
    def testPolicy1(self):
        self.ds.applyPolicy(policyEvaluation.PolicyString('101001010'))
        s = self.ds.getSpecifications(((0,0),(1,0),(1,1),(2,1),(2,2),(2,3),(3,0),(3,1)))
        self.assertEqual(s["race"], ["Black or African American alone"]) 
        self.assertEqual(s["sex"], ["Female", "Male"]) 
        self.assertEqual(s["age"], [35, 100, 101]) 
        self.assertEqual(s["county"], ["Blount County", "Davidson County"])     
class TranslationDictionaryTestCase(DatasetTestCase):
    def testMostSpecific(self):
        td = self.ds.translationDictionary(policyEvaluation.PolicyString.mostSpecific(9))
        for word in self.ds.vocab:
            self.assertEqual([word], td[word])
    def testMostGeneral(self):
        td = self.ds.translationDictionary(policyEvaluation.PolicyString.mostGeneral(9))
        self.assertEqual([(0,0),(0,1)], td[(0,0)])
        self.assertEqual([(1,0),(1,1)], td[(1,0)])
        self.assertEqual([(2,0),(2,1),(2,2),(2,3),(2,4),(2,5),(2,6)], td[(2,0)])
        self.assertEqual([(3,0),(3,1)], td[(3,0)])
    def testPolicy1(self):
        td = self.ds.translationDictionary(policyEvaluation.PolicyString('101001010'))
        self.assertEqual([(0,0)], td[(0,0)])
        self.assertEqual([(1,0), (1,1)], td[(1,0)])
        self.assertEqual([(2,0)], td[(2,0)])
        self.assertEqual([(3,0),(3,1)], td[(3,0)])
   
class EvaluatorTestCase(unittest.TestCase):
    def setUp(self):
        vocab = pickle.load(open("../data/test/vocab.pckl", 'r'))   
        fields = {0:"race", 1:"sex", 2:"age", 3:"county"}
        dset = csv.reader(open("../data/test/dsets/testDataSource_5.csv", 'r'))
        prior = pickle.load(open("../data/test/prior.pckl", 'r'))
        ps = setUpTestDatabase()
        self.s = policyEvaluation.Evaluator(vocab, fields, dset, prior, ps)
class EvaluatePolicyTestCase(EvaluatorTestCase):
    def setUp(self):
        EvaluatorTestCase.setUp(self)
    def testSpecific(self):
        r = self.s.evaluatePolicy(policyEvaluation.PolicyString.mostSpecific(9))
        self.assertAlmostEqual(r,0.3076358616) 
    def testGeneral(self):
        r = self.s.evaluatePolicy(policyEvaluation.PolicyString.mostGeneral(9))
        self.assertAlmostEqual(r,0.000803729) 
    def testPolicy1(self):
        r = self.s.evaluatePolicy(policyEvaluation.PolicyString('101001010'))
        self.assertAlmostEqual(r,0.00795811) 
    def testPolicy2(self):
        r = self.s.evaluatePolicy(policyEvaluation.PolicyString('010011011'))
        self.assertAlmostEqual(r,0.0550069300) 
class BelowThresholdTestCase(EvaluatorTestCase):
    def setUp(self):
        EvaluatorTestCase.setUp(self)        
        self.s.previousPolicies = {policyEvaluation.PolicyString("101010"):.2,
                                   policyEvaluation.PolicyString("111000"):.6} 
    def testPolicy1(self):
        self.assertTrue(self.s.belowThreshold(policyEvaluation.PolicyString("001010"), .5))
    def testPolicy2(self):
        self.assertFalse(self.s.belowThreshold(policyEvaluation.PolicyString("111100"), .5))

class PolicyConstructorTestCase(unittest.TestCase):
    def setUp(self):
        vocab = pickle.load(open("../data/test/vocab.pckl", 'r'))   
        fields = {0:"race", 1:"sex", 2:"age", 3:"county"}
        self.c = policyEvaluation.PolicyConstructor(vocab,fields)
    def testInitial(self):
        pass
        #print self.c.divisions
        #print self.c.getPolicy()
class HarvestPolicyTestCase(PolicyConstructorTestCase):
    def testInitial(self):
        self.c.harvestPolicy(policyEvaluation.PolicyString('101001010'))
        #print self.c.divisions
class ModNBinsTestCase(PolicyConstructorTestCase):
    def testInitial(self):
        self.c.modNBins("age", 5)
        print self.c.divisions
        self.c.pprintPolicy(self.c.getPolicy())
class MatchNCharacters(PolicyConstructorTestCase):
    def testInitial(self):
        self.c.matchNCharacters("age", 1)
        print self.c.divisions
        self.c.pprintPolicy(self.c.getPolicy())          
if __name__ == "__main__":
    #import sys;sys.argv = ['', 'Test.testName']
    unittest.main()